local class = require 'hump.class'
local mathutils = require 'utilities.mathutils'

AI = class{
  function(self, server, aitype, id)
    self.server = server
    self.aitype = aitype
    self.id = id
    
    self:reinitialize()
  end
}

function AI:reinitialize()
  self.server:shipNew(self.id)
end

function AI:keepStationary(ship, v, vangle, cangle, dt)
  local desiredAngle = vangle + math.pi
  local delta = mathutils.clamp(desiredAngle - cangle, -math.pi, math.pi, true)
  ship:rotate(delta, dt)
  if v > 1 and math.abs(delta) < math.pi/4 then
    ship:accelerate(dt)
  end
end

function AI:update(dt)
  if self.server:running() then
    if not self:isReady() then
      local goReady = false
      for k,v in pairs(self.server.ships) do
        if v:isReady() then
          goReady = true
        end
      end
      if goReady then
        self:ready()
      end
    end
  
    local ship = self.server.ships[self.id]
    if ship and self:isReady() then
      local vx, vy = ship:velocity()
      local cx, cy = ship:center()
      local v = math.sqrt(vx^2+vy^2)
      local vangle = math.atan2(vy, vx)
      local currAngle = ship:rotation() - math.pi / 2
      if self.aitype == 'stationary' then
        self:keepStationary(ship, v, vangle, currAngle, dt)
        ship:shoot(dt)
      elseif self.aitype == 'randomRotationalStationary' then
        if v < 5 then
          ship:accelerate(dt)
          ship:rotate(math.random(-2, 2)*math.pi, dt)
        else
          self:keepStationary(ship, v, vangle, currAngle, dt)
        end
        ship:shoot(dt)
      elseif self.aitype == 'targetedRotationalStationary' then
        local maxvel = 10
        if v < maxvel then
          local mindelta = 2*math.pi
          for key,val in pairs(self.server.ships) do
            if key ~= self.id and val:alive() then
              local valx, valy = val:center()
              local delta = mathutils.clamp(math.atan2(valy-cy, valx-cx)-currAngle, -math.pi, math.pi, true)
              if math.abs(delta) < math.abs(mindelta) then
                mindelta = delta
              end
            end
          end
          ship:rotate(mathutils.clamp(mindelta*math.pi, -math.pi, math.pi), dt)
          if math.abs(mindelta) < 0.1 then
            local vcdelta = mathutils.clamp(vangle + math.pi - currAngle, -math.pi, math.pi, true)
            if v < 3 * maxvel / 4 or math.abs(vcdelta) > math.pi / 2 then
              ship:accelerate(dt)
            end
            ship:shoot(dt)
          end
        else
          self:keepStationary(ship, v, vangle, currAngle, dt)
          ship:shoot(dt)
        end
      elseif self.aitype == 'kamikaze' then
        local mindelta = 2*math.pi
          for key,val in pairs(self.server.ships) do
            if key ~= self.id and val:alive() then
              local valx, valy = val:center()
              local delta = mathutils.clamp(math.atan2(valy-cy, valx-cx)-currAngle, -math.pi, math.pi, true)
              if math.abs(delta) < math.abs(mindelta) then
                mindelta = delta
              end
            end
          end
        ship:rotate(mathutils.clamp(mindelta*math.pi, -math.pi, math.pi), dt)
        if math.abs(mindelta) < math.pi/8 and v < 10 then
          ship:accelerate(dt)
        end
        ship:shoot(dt)
      end
    end
  end
end

function AI:ready()
  self.server:shipReady(self.id)
end

function AI:unready()
  self.server:shipUnready(self.id)
end

function AI:isReady()
  return self.server:shipIsReady(self.id)
end
